1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.systems.hotload; 12 13 version(Load_DScript): 14 import hip.filesystem.hipfs; 15 import hip.util.system; 16 import hip.util.path; 17 import hip.console.log; 18 import hip.error.handler; 19 20 final class HotloadableDLL 21 { 22 void* lib; 23 24 immutable string trueLibPath; 25 void delegate (void* libPointer) onDllLoad; 26 string tempDll; 27 string tempPdb; 28 this(string path, void delegate (void* libPointer) onDllLoad) 29 { 30 ErrorHandler.assertExit(path != null, "DLL path should not be null: 31 Call `dub -c script -- path/to/project` dub -c script requires that argument."); 32 33 import hip.util.path; 34 import hip.util.file; 35 36 path = absolutePath(path, getcwd).normalizePath; 37 if(HipFS.absoluteExists(path) && HipFS.absoluteIsDir(path)) 38 path = joinPath(path, path.filenameNoExt); 39 if(!dynamicLibraryIsLibNameValid(path)) 40 path = dynamicLibraryGetLibName(path); 41 trueLibPath = path; 42 this.onDllLoad = onDllLoad; 43 load(path); 44 } 45 protected bool load(string path) 46 { 47 if(!HipFS.absoluteExists(path)) 48 { 49 import hip.console.log; 50 logln("Path '", path, "' does not exists while trying to find for a HotloadableDLL"); 51 return false; 52 } 53 //Create dll_hiptempdll 54 tempDll = getTempName(path); 55 56 copy(path, tempDll); 57 58 // version(Windows) 59 // {{ 60 // import std.process:executeShell; 61 // import hip.util.path; 62 // string tempDirectory = joinPath(path.dirName, "temp"); 63 // mkdirRecurse(tempDirectory); 64 65 // string thePdb = path.extension("pdb"); 66 // tempPdb = getTempName(thePdb); 67 // if(exists(thePdb)) 68 // { 69 // copy(thePdb, joinPath(tempDirectory, thePdb.baseName)); 70 // rename(thePdb, tempPdb); 71 // } 72 73 // }} 74 75 76 loglnInfo("Loading dll ", path); 77 lib = dynamicLibraryLoad(tempDll); 78 if(onDllLoad && lib != null) 79 onDllLoad(lib); 80 else if(lib == null) 81 loglnError("Could not load dll ", path); 82 return lib != null; 83 } 84 /** 85 * 86 * Params: 87 * path = File path 88 * Returns: filePath.(ext)_hiptempdll 89 */ 90 static string getTempName(string path) 91 { 92 import hip.util.string; 93 string d = dirName(path); 94 string n = baseName(path); 95 string ext = extension(n); 96 97 int ind = lastIndexOf(n, "_hiptemp"); 98 if(ind != -1) 99 return path; 100 return joinPath(d, n[0..$-(ext.length+1)]~"_hiptemp."~ext); 101 } 102 103 void reload() 104 { 105 if(lib != null) 106 { 107 dynamicLibraryRelease(lib); 108 lib = null; 109 } 110 load(trueLibPath); 111 } 112 113 void dispose() 114 { 115 import hip.error.handler; 116 if(lib != null) 117 { 118 if(!dynamicLibraryRelease(lib)) 119 return ErrorHandler.showErrorMessage("Could not unload the dll ", tempDll); 120 121 foreach(remFile; [tempDll, tempPdb]) 122 { 123 try 124 { 125 if(remFile && !HipFS.absoluteRemove(remFile)) 126 { 127 ErrorHandler.showErrorMessage("Could not remove ", remFile); 128 } 129 } 130 catch(Exception e) 131 { 132 ErrorHandler.showErrorMessage("Could not remove file ", remFile); 133 } 134 } 135 } 136 } 137 } 138 139 private void copy(string input, string output) 140 { 141 import hip.filesystem.hipfs; 142 void[] data; 143 if(!HipFS.absoluteRead(input, data)) 144 throw new Error("Could not read input file "~input); 145 146 try 147 { 148 if(!HipFS.absoluteWrite(output, data)) 149 throw new Error("Could not copy from "~input~" to "~output); 150 } 151 catch (Exception e) { 152 153 } 154 155 }